package com.zlq.cn.service.un;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zlq.cn.admin.domain.SysConfig;
import com.zlq.cn.admin.service.SysConfigService;
import com.zlq.cn.api.ApiCodeEnum;
import com.zlq.cn.api.ResponseException;
import com.zlq.cn.bootstrap.SignApiBootstrap;
import com.zlq.cn.config.OkhttpConfig;
import com.zlq.cn.dto.param.FanyiFeedbackParam;
import com.zlq.cn.dto.param.VipUpParam;
import com.zlq.cn.dto.vo.SignCommonParam;
import com.zlq.cn.entity.*;
import com.zlq.cn.enums.SubtypeEnum;
import com.zlq.cn.mapper.un.FanyiUserMapper;
import com.zlq.cn.util.ImeiUtil;
import com.zlq.cn.util.JWTUtils;
import com.zlq.cn.util.StringUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zhoucl
 * @since 2022-03-05
 */
@Slf4j
@Service
public class FanyiUserService extends ServiceImpl<FanyiUserMapper, FanyiUser> implements ApplicationRunner {

    @Resource
    private IosService iosService;

    @Resource
    private VipLogService vipLogService;

    @Resource
    private VipOrderService vipOrderService;

    @Resource
    private VipLevelService vipLevelService;

    @Resource
    private VipOrderUpService vipOrderUpService;

    @Resource
    private SuggestRecordService suggestRecordService;

    @Resource
    private SysConfigService sysConfigService;

    private boolean isRun = false;

    public FanyiUser login(String iosToken, String project) {
        SignCommonParam param = SignApiBootstrap.get();
        Integer count = super.lambdaQuery()
                .eq(FanyiUser::getIosToken, iosToken)
                .eq(FanyiUser::getProject, project)
                .count();
        if (count == null || count == 0) {
            param.setImei(ImeiUtil.generateImei())
                    .setIosToken(iosToken);
        }
        return login(project);
    }

    public FanyiUser commonLogin() {
        SignCommonParam param = SignApiBootstrap.get();
        FanyiUser fanyiUser = login(param.getPackageName());
        SysConfig yaoqiuvip = sysConfigService.getById("YAOQIUVIP_" + param.getPackageName());
        if (yaoqiuvip != null) {
            fanyiUser.setYaoqiuvip(yaoqiuvip.getValue());
        }
        if ("com.maomaotech.enwrite".equals(param.getPackageName()) && fanyiUser.getVipStartTime() == null) {
            LocalDateTime vipStartTime = LocalDateTime.now();
            fanyiUser.setVipStartTime(vipStartTime);
            fanyiUser.setVipEndTime(vipStartTime.plusDays(7));
            super.lambdaUpdate()
                    .set(FanyiUser::getVipStartTime, fanyiUser.getVipStartTime())
                    .set(FanyiUser::getVipEndTime, fanyiUser.getVipEndTime())
                    .eq(FanyiUser::getFanyiUserImei, fanyiUser.getFanyiUserImei())
                    .update();
        }
        return fanyiUser;
    }

    /**
     * 用户登录/注册
     *
     * @return 用户信息
     */
    public FanyiUser login(String project) {
        SignCommonParam param = SignApiBootstrap.get();
        FanyiUser fanyiUser = super.lambdaQuery()
                .eq(FanyiUser::getFanyiUserImei, param.getImei())
                .one();
        if (fanyiUser == null) {
            fanyiUser = new FanyiUser()
                    .setFanyiUserImei(param.getImei())
                    .setCreateTime(LocalDateTime.now())
                    .setLastLoginTime(LocalDateTime.now())
                    .setIosToken(param.getIosToken())
                    .setProject(project);
            super.save(fanyiUser);
        } else {
            if (Objects.nonNull(fanyiUser.getIsDisable()) && 1 == fanyiUser.getIsDisable()) {
                ResponseException.resultError(ApiCodeEnum.API_ERROR.getCode(), "网络异常");
            }
            FanyiUser updateFanyiUser = new FanyiUser()
                    .setFanyiUserImei(param.getImei())
                    .setLastLoginTime(LocalDateTime.now());
            super.updateById(updateFanyiUser);
        }
        fanyiUser.setUseDay(Math.max(1, Math.abs(fanyiUser.getCreateTime().until(LocalDateTime.now(), ChronoUnit.DAYS))));
        this.updateSurplusDay(fanyiUser);

        fanyiUser.setToken(SecureUtil.md5(sysConfigService.getById("TOKEN_MD5").getValue()));
        return fanyiUser;
    }

    @SneakyThrows
    public String microsoftTextTranslate(JSONObject param) {
        String location = "southeastasia";
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, "[{\"Text\": \"" + param.getString("text") + "\"}]");
        Request request = new Request.Builder()
                .url(String.format("https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&from=%s&to=fr&to=%s",
                        param.getString("from"), param.getString("to")))
                .post(body)
                .addHeader("Ocp-Apim-Subscription-Key", "7551a35260f04a478f2f1e0a5cda5e69")
                .addHeader("Ocp-Apim-Subscription-Region", location)
                .addHeader("Content-type", "application/json")
                .build();
        Response response = OkhttpConfig.okHttpClient.newCall(request).execute();
        return response.body().string();
    }

    @SneakyThrows
    public static void main(String[] args) {
//        MicrosoftTranslate
        OkHttpClient client = new OkHttpClient();

//        System.out.println(string);
    }

    /**
     * 苹果支付回调
     */
    @Transactional(rollbackFor = Exception.class)
    public void iosCallback(JSONObject param) {
        String signedPayload = JWTUtils.verify(param.getString("signedPayload"));
        if (StringUtils.isNotEmpty(signedPayload)) {
            JSONObject signedPayloadJson = JSONObject.parseObject(Base64.decodeStr(signedPayload));
            String notificationType = signedPayloadJson.getString("notificationType");
            String subtype = signedPayloadJson.getString("subtype");
            JSONObject data = signedPayloadJson.getJSONObject("data");
            String signedTransactionInfo = data.getString("signedTransactionInfo");
            JSONObject transactionInfo = JSON.parseObject(Base64.decodeStr(JWTUtils.verify(signedTransactionInfo)));

            data.put("signedTransactionInfo", transactionInfo);
            signedPayloadJson.put("data", data);

            String transactionId = transactionInfo.getString("transactionId");
            String originalTransactionId = transactionInfo.getString("originalTransactionId");
            String bundleId = transactionInfo.getString("bundleId");
            String productId = transactionInfo.getString("productId");

            log.info("notificationType==>" + notificationType);
            log.info("subtype==>" + subtype);
            log.info("transactionInfo==>" + transactionInfo);
            // 处理订阅成功
            if (SubtypeEnum.DID_RENEW.code.equals(notificationType) || SubtypeEnum.SUBSCRIBED.code.equals(notificationType)) {
                VipOrderUp vipOrderUp = vipOrderUpService.lambdaQuery().eq(VipOrderUp::getOriginalTransactionId, originalTransactionId).one();
                VipOrder vipOrder = new VipOrder()
                        .setVipKey(productId)
                        .setTransactionId(transactionId)
                        .setOriginalTransactionId(originalTransactionId)
                        .setBundleId(bundleId)
                        .setLog(signedPayloadJson.toJSONString())
                        .setCreateTime(LocalDateTime.now());
                // 还未上报用户单号关系，先存储一个待处理订单
                if (vipOrderUp == null) {
                    vipOrder.setStatus(2);
                    vipOrderService.save(vipOrder);
                    isRun = true;
                } else {
                    String userImei = vipOrderUp.getUserImei();
                    FanyiUser fanyiUser = super.getById(userImei);
                    VipLevel vipLevel = vipLevelService.findVipLevelByVipKey(productId);
                    plusVipTime(fanyiUser, vipLevel);
                    super.updateById(fanyiUser);
                    vipOrder.setUserImei(userImei);
                    vipOrder.setStatus(1);
                    vipOrderService.save(vipOrder);
                }
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void iosOrderUp(JSONObject param) {
        FanyiUser fanyiUser = SignApiBootstrap.requestFanYiUser();
        String orderNo = param.getString("orderNo");
        String productId = param.getString("productId");
        VipOrderUp vipOrderUp = new VipOrderUp()
                .setUserImei(fanyiUser.getFanyiUserImei())
                .setProductId(productId)
                .setOriginalTransactionId(orderNo)
                .setCreateTime(LocalDateTime.now());
        try {
            vipOrderUpService.save(vipOrderUp);
        } catch (Exception e) {
            log.error("上报vip保存失败", e);
        }
        // 检查有没有待处理的单据
        List<VipOrder> vipOrders = vipOrderService.lambdaQuery().eq(VipOrder::getOriginalTransactionId, orderNo).list();
        if (CollectionUtil.isNotEmpty(vipOrders)) {
            VipLevel vipLevel = vipLevelService.findVipLevelByVipKey(productId);
            for (VipOrder vipOrder : vipOrders) {
                vipOrder.setUserImei(fanyiUser.getFanyiUserImei())
                        .setStatus(1);
                plusVipTime(fanyiUser, vipLevel);
                vipOrderService.updateById(vipOrder);
            }
            super.updateById(fanyiUser);
        }
    }

    /**
     * 翻译用户vip开通上报
     *
     * @param vipUpParam vip开通参数
     * @return 操作结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Object vipUp(VipUpParam vipUpParam) {
        FanyiUser fanyiUser = super.getById(SignApiBootstrap.get().getImei());
        Assert.notNull(fanyiUser, "用户不存在");
        if (!vipUpParam.isCheckBuyAppVerify() ||
                iosService.buyAppVerify(vipUpParam.getTransactionId(), vipUpParam.getReceipt(), fanyiUser.getProject())) {
            Integer count = vipLogService.lambdaQuery()
                    .eq(VipLog::getOrderNo, vipUpParam.getTransactionId())
                    .count();
            Assert.state(count <= 0, "该流水号已被使用");
            VipLog vipLog = new VipLog();
            vipLog.setOrderNo(vipUpParam.getTransactionId());
            vipLog.setReceipt(vipUpParam.getReceipt());
            vipLog.setOrderType(SignApiBootstrap.get().getImei());
            vipLog.setCreateTime(LocalDateTime.now());
            vipLog.setUpdateTime(LocalDateTime.now());
            vipLogService.save(vipLog);

            VipLevel vipLevel = new VipLevel();
            vipLevel.setVipDayNum(vipUpParam.getOpenDay());
            plusVipTime(fanyiUser, vipLevel);
            return super.updateById(fanyiUser);
        }
        return Boolean.TRUE;
    }


    @Override
    public void run(ApplicationArguments args) throws Exception {
        isRun = true;
        runPlusVipTimeTask();
    }

    @Scheduled(fixedDelay = 10000)
    public void runPlusVipTimeTask() {
        if (isRun) {
            List<VipOrder> list = vipOrderService.lambdaQuery()
                    .eq(VipOrder::getStatus, 2)
                    .apply("IFNULL(error_num,0) <= {0}", 10)
//                    .le(VipOrder::getErrorNum, 10)
                    .list();
            if (CollectionUtils.isNotEmpty(list)) {
                for (VipOrder vipOrder : list) {
                    VipOrderUp vipOrderUp = vipOrderUpService.lambdaQuery().eq(VipOrderUp::getOriginalTransactionId, vipOrder.getOriginalTransactionId()).one();
                    if (vipOrderUp != null) {
                        FanyiUser fanyiUser = super.getById(vipOrderUp.getUserImei());
                        VipLevel vipLevel = vipLevelService.findVipLevelByVipKey(vipOrder.getVipKey());
                        vipOrder.setUserImei(fanyiUser.getFanyiUserImei())
                                .setStatus(1);
                        plusVipTime(fanyiUser, vipLevel);
                    }
                    Integer errorNum = ObjectUtils.defaultIfNull(vipOrder.getErrorNum(), 0);
                    vipOrder.setErrorNum(errorNum + 1);
                }
                vipOrderService.updateBatchById(list);
            } else {
                isRun = false;
            }
        }
    }

    private void plusVipTime(FanyiUser fanyiUser, VipLevel vipLevel) {
        log.info("本次开通等级==>" + JSON.toJSONString(vipLevel));
        // 有免费天数，查询当前用户在在改产品id下是否已经使用过免费3天，没有3天
        if (vipLevel.getVipFreeDayNum() != null && vipLevel.getVipFreeDayNum() > 0) {
            Integer count = vipOrderService.lambdaQuery()
                    .eq(VipOrder::getUserImei, fanyiUser.getFanyiUserImei())
                    .eq(VipOrder::getVipKey, vipLevel.getVipKey())
//                    .eq(VipOrder::getStatus, 1)
                    .count();
            if (count == null || count == 0) {
                vipLevel.setVipDayNum(vipLevel.getVipFreeDayNum());
                vipLevel.setVipMonthNum(0);
                log.info("首次免费天数==>" + vipLevel.getVipDayNum());
            }
        }
        LocalDateTime vipStartTime = fanyiUser.getVipStartTime();
        LocalDateTime vipEndTime = fanyiUser.getVipEndTime();
        Integer vipMonthNum = vipLevel.getVipMonthNum();
        Integer vipDayNum = vipLevel.getVipDayNum();
        log.info("本次开通天数==>" + vipDayNum);
        log.info("本次开通月数==>" + vipMonthNum);
        Function<LocalDateTime, LocalDateTime> function = localDateTime -> {
            if (localDateTime != null && vipDayNum != null && vipDayNum > 0) {
                localDateTime = localDateTime.plusDays(vipDayNum);
            }
            if (localDateTime != null && vipMonthNum != null && vipMonthNum > 0) {
                localDateTime = localDateTime.plusMonths(vipMonthNum);
            }
            return localDateTime;
        };
        // 初次开通，直接增加时间
        if (vipStartTime == null) {
            vipStartTime = LocalDateTime.now();
            fanyiUser.setVipStartTime(vipStartTime);
            fanyiUser.setVipEndTime(function.apply(vipStartTime));
            // 开通过
        } else if (vipEndTime != null) {
            // 校验是否过期,过期则开始结束重新生成
            if (vipEndTime.isBefore(LocalDateTime.now())) {
                vipStartTime = LocalDateTime.now();
                fanyiUser.setVipStartTime(vipStartTime);
                fanyiUser.setVipEndTime(function.apply(vipStartTime));
            } else {
                fanyiUser.setVipEndTime(function.apply(vipEndTime));
            }
        }
    }

    public void updateSurplusDay(FanyiUser fanyiUser) {
        if (fanyiUser == null) {
            return;
        }
        LocalDateTime vipEndTime = fanyiUser.getVipEndTime();
        long surplusDay = 0;
        if (vipEndTime != null && vipEndTime.isAfter(LocalDateTime.now())) {
            surplusDay = Math.abs(vipEndTime.toLocalDate().until(LocalDate.now(), ChronoUnit.DAYS));
        }
        fanyiUser.setSurplusDay(surplusDay);
        if (fanyiUser.getVipEndTime() != null) {
            if (surplusDay > 3650) {
                fanyiUser.setMembershipExpirationDate("终身会员");
            } else {
                fanyiUser.setMembershipExpirationDate(String.format("您的会员将于%s日到期", DateTimeFormatter.ofPattern("yyyy-MM-dd").format(fanyiUser.getVipEndTime())));
            }
        }
    }

    public Object feedback(FanyiFeedbackParam fanyiFeedbackParam) {
        SuggestRecord suggestRecord = new SuggestRecord()
                .setPhone(SignApiBootstrap.get().getImei())
                .setContent(fanyiFeedbackParam.getContent())
                .setSubmitdate(LocalDateTime.now());
        return suggestRecordService.save(suggestRecord);
    }

    public Object vipPermanent() {
        FanyiUser fanyiUser = SignApiBootstrap.requestFanYiUser();
        fanyiUser.setVipEndTime(LocalDateTime.now().plusYears(99));
        this.updateById(fanyiUser);
        return null;
    }
}
